package utils;

import java.sql.*;

/**
 * 注意：工具类是直接用类名访问方法的，所以里面的所有成员都是写成static的
 */
public class DBUtil {
    //1 定义好数据库地址，用户名，密码，utf8编码
    private static final String URL = "jdbc:mysql:///attdb?characterEncoding=utf8";
    // 写好一行，可以直接复制CTRL+D 是复制
    private static final String USER = "root";
    private static final String PWD = "root";

    //2 用静态代码块 注册驱动
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver"); // 注意这里mysql.jdbc与前面的URL中 jdbc:mysql 刚好相反，要记一下
        } catch (ClassNotFoundException e) {
            System.out.println("驱动注册失败");
            throw new RuntimeException(e);
        }
    }
    //3 获取连接对象的方法,返回值类型先写成void，等代码里生成出Connection，再把Connection替换掉void
    public static Connection getConn() throws SQLException {  // 这里的异常可以抛出
        Connection conn = DriverManager.getConnection(URL, USER, PWD);// 写表达式的时候，要活用万能快捷键ALT+回车
        // 当要用一个变量接收一个内容的时候，先写好右侧的内容，再按ALT+回车，选择引入局部变量，就会自动生成左侧的代码Connection conn
        return conn; // 将生成的连接对象返回
    }
    //4 通用的查询方法，负责查询所有和有条件的查询

    /**
     * 通用的查询方法，要接收一个SQL语句，返回结果集，方法返回值类型一样先写void,等结果集出来了，再替换
     * 此时，再思考一个问题，查询方法接收的SQL语句，可能含有？号，就要改造方法，接收？号对应的参数，并在预编译时把参数设置到？上
     */
    public static ResultSet query(String sql,Object... keys){
        // 加一个可变参数keys,类型设置为Object...
        //1 获取连接对象
        ResultSet rs = null;
        try {
            Connection conn = getConn();
            //2 获取执行SQL执行对象，并预编译
            PreparedStatement pst = conn.prepareStatement(sql);
            //2.5 预编译后，要遍历keys,将里面的参数一一取出来，赋值给对应的？号
            // 注意：keys是本质上是数组，遍历时，是从0开始，而？号的遍历是从1开始
            for (int i = 0; i < keys.length; i++) {
                // 所以keys元素的值与？号的关系就是i=>i=1
                pst.setObject((i+1),keys[i]);// pst对象有个设置参数的方法，因为keys是Object类型，所以我们就用pst.setObject（这里有两个参数，前面一个代表？号，后面一个代表参数值）方法
            }
            //3 执行SQL得到结果集
            rs = pst.executeQuery();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        //4 返回结果集
        return rs;
        //5 统一处理异常 ctrl+alt+T
    }

    //5 通用的update方法 ,负责添加，删除，修改,可以省略时间，可以直接复制通用的查询方法，改返回值，改方法名，改执行方法

    /**
     * update 方法，返回的是一个整数，表示受影响行数
     * @param sql
     * @param keys
     * @return
     */
    public static int update(String sql,Object... keys){
        // 加一个可变参数keys,类型设置为Object...
        //1 获取连接对象
        int num=0; // 这里不写i是因为下面已经有i了，默认值写0
        try {
            Connection conn = getConn();
            //2 获取执行SQL执行对象，并预编译
            PreparedStatement pst = conn.prepareStatement(sql);
            //2.5 预编译后，要遍历keys,将里面的参数一一取出来，赋值给对应的？号
            // 注意：keys是本质上是数组，遍历时，是从0开始，而？号的遍历是从1开始
            for (int i = 0; i < keys.length; i++) {
                // 所以keys元素的值与？号的关系就是i=>i=1
                pst.setObject((i+1),keys[i]);// pst对象有个设置参数的方法，因为keys是Object类型，所以我们就用pst.setObject（这里有两个参数，前面一个代表？号，后面一个代表参数值）方法
            }
            //3 执行SQL得到结果集
            num = pst.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        //4 返回结果集
        return num;
        //5 统一处理异常 ctrl+alt+T
    }

    // 这样工具类就写好了


}
